package util;

import httplib.HTMLFileHandler;

/**
 * Makes accessing files safe from a concurrency point of view
 * The ConcurrentAccess class solves the First Readers Writeres problem
 * The Class is a singleton. Get the instance of the class by calling the getInstance() method
 * @author dzgonjan
 *
 */
public class ConcurrentAccess {
	private int numReaders;
	private static ConcurrentAccess singleton;
	
	/**
	 * The constructor. It is private because the class is a singleton
	 */
	private ConcurrentAccess(){
		
	}
	
	/**
	 * Returns the only instance of this class. If one does not exist, it is created
	 * @return
	 */
	public static ConcurrentAccess getInstance(){
		if (ConcurrentAccess.singleton == null) 
			ConcurrentAccess.singleton = new ConcurrentAccess();
		
		return ConcurrentAccess.singleton;
	}
	
	/**
	 * Writes data to disk. Only works if there isn't another writer already writing,
	 * or if there are no readers currently reading.
	 * This method does not do the actual reading. That is left up to the FileHandler object
	 * Instead this class simply makes sure that the access is safe
	 * @param writer - The writer FileHandler which writes to the file
	 * @param headerData - data to be passed to the FileHandler
	 * @return
	 */
	public synchronized String put(HTMLFileHandler writer, String headerData){
		while (numReaders>0){
			try{
				this.wait();
			} catch(InterruptedException e){
				System.out.println(e.getMessage());
			}
		}
		
		return writer.handleFile(headerData);
	}
	
	/**
	 * Reads data from disk. Only works if there are no writers currently writing to the disk
	 * Multiple readers can read at the same time
	 * Does not perform the actual read - that is left up to the
	 * FileHandler object. This method simply makes sure that the access is safe
	 * @param reader
	 * @param fileName
	 * @return
	 */
	public String get(HTMLFileHandler reader, String fileName){
		synchronized(this){
			numReaders++;
		}
		
		String returnMessage = reader.handleFile(fileName);
		
		synchronized(this){
			numReaders--;
			this.notifyAll();
		}
		
		return returnMessage;
	}
}
